﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Rappelz.GameServer.Network;
using Rappelz.GameServer.Network.GameClient;

namespace Rappelz.GameServer
{
    public class NPC : Creature
    {
        public enum NPCStatus : int
        {
            Normal = 0,
            Tracking = 1,
            FindAttackPos = 2,
            Attack = 3,
            Dead = 4,
        }
// 
// UserDefinedType:   NPCDeadHandler
// VTable         :     , Type:  *
// Function       :     public void onNPCDead(struct StructNPC *)
// Function       :     public void NPCDeadHandler(const struct StructNPC::NPCDeadHandler &)
// Function       :     public void NPCDeadHandler()
// Function       :     public struct StructNPC::NPCDeadHandler & operator=(const struct StructNPC::NPCDeadHandler &)
// Function       :   public void StructNPC(const struct StructNPC &)

        public NPC(NPCBase info)
        {
//             v3->m_vQuestLink_Start._Myfirst = 0;
//             v3->m_vQuestLink_Start._Mylast = 0;
//             v3->m_vQuestLink_Start._Myend = 0;
//             v3->m_vQuestLink_Progress._Myfirst = 0;
//             v3->m_vQuestLink_Progress._Mylast = 0;
//             v3->m_vQuestLink_Progress._Myend = 0;
//             v3->m_vQuestLink_End._Myfirst = 0;
//             v3->m_vQuestLink_End._Mylast = 0;
//             v3->m_vQuestLink_End._Myend = 0;
//             v3->m_vQuest._Myfirst = 0;
//             v3->m_vQuest._Mylast = 0;
//             v3->m_vQuest._Myend = 0;
//             v3->m_pathFindPolygons._Myfirst = 0;
//             v3->m_pathFindPolygons._Mylast = 0;
//             v3->m_pathFindPolygons._Myend = 0;

            MemoryPool.AllocMiscHandle(this);
            this.m_nArObjectType = 1;

            this.m_bHasQuest = false;
            this.m_BaseInfo = info;
            this.m_szName = GameContent.GetString(info.text_id) + " " + GameContent.GetString(info.name_text_id);

            this.m_nLastEnemyDistance = 0.0f;
//            this.m_Roamer = null;
//            this.m_DeadHandler = null;
            this.m_nStatus = 0;
            this.m_bComeBackHome = false;
            this.m_nLastTrackTime = 0;
            this.m_RespawnX = info.x;
            this.m_RespawnY = info.y;
            if (info.attackable == 0)
                this.m_StatusFlag |= Creature.StatusFlags.Invincible;
//            XSEH::IncreaseAllocCount("StructNPC", 1);

        }
// Function       :   public void StructNPC::~StructNPC()
// Function       :   public bool StructNPC::ProcDelete()

        public NPCStatus GetStatus()
        {
            return (NPCStatus) this.m_nStatus;
        }

        public void SetStatus(NPCStatus status)
        {
            if (this.m_nStatus != (int)status && status != NPCStatus.Dead)
                Messages.BroadcastStatusMessage(this);
            this.m_nStatus = (int)status;
        }

        public override string GetName()
        {
            return this.m_szName;
        }

        public override bool IsNPC()
        {
            return true;
        }

        public int GetNPCID()
        {
            return this.m_BaseInfo.id;
        }

        public int GetQuestTextId(int code, int progress)
        {
            List<QuestLink> wql = null;
            if (progress == 2)
                wql = this.m_vQuestLink_End;
            else if (progress == 1)
                wql = this.m_vQuestLink_Progress;
            else
                wql = this.m_vQuestLink_Start;

            foreach (QuestLink ql in wql)
            {
                if (ql.code == code)
                {
                    if (progress == 0)
                        return ql.nStartTextId;
                    if (progress == 1)
                        return ql.nInProgressTextId;
                    if (progress == 2)
                        return ql.nEndTextId;
                }
            }
            return 0;
        }

        public int GetProgressFromTextId(int code, int textId)
        {
            foreach (QuestLink ql in this.m_vQuestLink_Start)
            {
                if (ql.code == code)
                {
                    if (textId == ql.nStartTextId)
                        return 0;
                    if (textId == ql.nInProgressTextId)
                        return 1;
                    if (textId == ql.nEndTextId)
                        return 2;
                }
            }

            foreach (QuestLink ql in this.m_vQuestLink_Progress)
            {
                if (ql.code == code)
                {
                    if (textId == ql.nStartTextId)
                        return 0;
                    if (textId == ql.nInProgressTextId)
                        return 1;
                    if (textId == ql.nEndTextId)
                        return 2;
                }
            }

            foreach (QuestLink ql in this.m_vQuestLink_End)
            {
                if (ql.code == code)
                {
                    if (textId == ql.nStartTextId)
                        return 0;
                    if (textId == ql.nInProgressTextId)
                        return 1;
                    if (textId == ql.nEndTextId)
                        return 2;
                }
            }
            return 0;
        }

        public int GetDialogTypeFromTextId(int code, int textId)
        {
            foreach (QuestLink ql in this.m_vQuestLink_Start)
            {
                if (ql.code == code)
                {
                    if (textId == ql.nStartTextId)
                        return 3;
                    if (textId == ql.nInProgressTextId)
                        return 7;
                    if (textId == ql.nEndTextId)
                        return 8;
                }
            }

            foreach (QuestLink ql in this.m_vQuestLink_Progress)
            {
                if (ql.code == code)
                {
                    if (textId == ql.nStartTextId)
                        return 3;
                    if (textId == ql.nInProgressTextId)
                        return 7;
                    if (textId == ql.nEndTextId)
                        return 8;
                }
            }

            foreach (QuestLink ql in this.m_vQuestLink_End)
            {
                if (ql.code == code)
                {
                    if (textId == ql.nStartTextId)
                        return 3;
                    if (textId == ql.nInProgressTextId)
                        return 7;
                    if (textId == ql.nEndTextId)
                        return 8;
                }
            }
            return 3;
        }

// Function       :   public const char * GetContactFunction()

        public void LinkQuest(QuestLink quest_link_info)
        {
            if (quest_link_info.bLF_Start)
                this.m_vQuestLink_Start.Add(quest_link_info);

            if (quest_link_info.bLF_Progress)
                this.m_vQuestLink_Progress.Add(quest_link_info);

            if (quest_link_info.bLF_End)
                this.m_vQuestLink_End.Add(quest_link_info);
        }

        public void ClearQuestLink()
        {
            this.m_vQuestLink_Start.Clear();
            this.m_vQuestLink_Progress.Clear();
            this.m_vQuestLink_End.Clear();
        }
// Function       :   public bool StructNPC::StartAttack(unsigned int, bool)

        public void SetAttacker(Creature pAttacker)
        {
            if (this.IsAttackableNPC())
            {
                if (this.m_hEnemy == 0)
                {
                    this.StartAttack(pAttacker.m_hHandle, false);
                }
            }
        }


        public void DoEachStartableQuest(Player pPlayer, NPCQuestFunctor fn)
        {
            foreach (QuestLink ql in this.m_vQuestLink_Start)
            {
                if (pPlayer.IsStartableQuest(ql.code,false))
                {
                    fn.run(pPlayer, ql);
                }
            }
        }

        public void DoEachInProgressQuest(Player pPlayer, NPCQuestFunctor fn)
        {
            foreach (QuestLink ql in this.m_vQuestLink_Progress)
            {
                if (pPlayer.IsInProgressQuest(ql.code))
                {
                    fn.run(pPlayer, ql);
                }
            }
        }

        public void DoEachFinishableQuest(Player pPlayer, NPCQuestFunctor fn)
        {
            foreach (QuestLink ql in this.m_vQuestLink_End)
            {
                if (pPlayer.IsFinishableQuest(ql.code))
                {
                    fn.run(pPlayer, ql);
                }
            }
        }

        public bool IsAttackableNPC()
        {
            return this.m_BaseInfo.attackable != 0;
        }
// Function       :   public bool HasQuest()

        public bool HasStartableQuest(Player player)
        {
            bool bHasProgressRandom = false;
            bool isstart = false;

            foreach (QuestLink ql in this.m_vQuestLink_Start)
            {
                QuestBase.QuestType qt = Quest.GetQuestBase(ql.code).nType;

                if (qt == QuestBase.QuestType.RandomKillIndividual || qt == QuestBase.QuestType.RandomCollect)
                {
                    if (player.IsInProgressQuest(ql.code)|| player.IsFinishableQuest(ql.code))
                    {
                        bHasProgressRandom = true;
                    }
                    else
                    {
                        if (player.IsStartableQuest(ql.code, true))
                            isstart = true;
                    }
                }
                else
                {
                    if (player.IsStartableQuest(ql.code, true))
                        return true;
                }
            }
            if (isstart && !bHasProgressRandom)
                return true;

            return false;
        }

        public bool HasInProgressQuest(Player player)
        {
            foreach (QuestLink ql in this.m_vQuestLink_Progress)
            {
                if(player.IsInProgressQuest(ql.code))
                    return true;
            }
            return false;
        }

        public bool HasFinishableQuest(Player player)
        {
            foreach (QuestLink ql in this.m_vQuestLink_End)
            {
                if (player.IsFinishableQuest(ql.code))
                    return true;
            }
            return false;
        }
// Function       :   public void SetReturnPosition(float, float)
// Function       :   public const struct NPCBase * GetNPCBase()
// Function       :   public bool StructNPC::IsEnemy(struct StructCreature *, bool)
// Function       :   public void SetDeadHandler(struct StructNPC::NPCDeadHandler *)
// Function       :   public bool IsFirstAttacker()
// Function       :   public float GetChaseRange()
// Function       :   public bool StructNPC::IsBattleMode()
// Function       :   public void SetRoamer(struct StructRoamer *)
// Function       :   public struct StructRoamer * GetRoamer()
// Function       :   public void StructNPC::onDead(struct StructCreature *, bool)
// Function       :   protected void findAttackablePosition(const struct ArPosition &, struct ArPosition &, float, float)
// Function       :   protected void StructNPC::processFirstAttack(unsigned long)
// Function       :   protected void StructNPC::comeBackHome(bool)
// Function       :   protected unsigned int GetEnemyUID()
// Function       :   protected void AI_processAttack(struct StructCreature *, unsigned long)
// Function       :   protected void StructNPC::AI_processAttack(unsigned long)
// Function       :   protected struct ArPosition getNonDuplicateAttackPos(struct StructCreature *)
// Function       :   protected void StructNPC::processWalk(unsigned long)
// Function       :   protected void StructNPC::processDead(unsigned long)
        public uint m_nLastTrackTime;                                               // 0xFE0
        public float m_nLastEnemyDistance;                                          // 0xFE4
        public int m_nStatus;                                                       // 0xFE8
        public float m_RespawnX;                                                    // 0xFEC
        public float m_RespawnY;                                                    // 0xFF0
        public bool m_bComeBackHome;                                                // 0xFF4
// Function       :   protected void StructNPC::onBeforeCalculateStat()
// Function       :   protected void StructNPC::onApplyAttributeAdjustment()
// Function       :   protected void StructNPC::onProcess(int)
// Function       :   protected const struct CreatureStat & StructNPC::GetBaseStat()
        public string m_szName;                                                     // 0xFF5
        public bool m_bHasQuest;                                                    // 0x103C
        public NPCBase m_BaseInfo;                                                  // 0x1040
        public List<QuestLink> m_vQuestLink_Start = new List<QuestLink>();          // 0x1044
        public List<QuestLink> m_vQuestLink_Progress = new List<QuestLink>();       // 0x1054
        public List<QuestLink> m_vQuestLink_End = new List<QuestLink>();            // 0x1064
        public List<int> m_vQuest = new List<int>();                                // 0x1074
// 
// Data           :   this+0x1084, Member, Type: class std::vector<X2D::Polygon<int> *,std::allocator<X2D::Polygon<int> *> >, m_pathFindPolygons
// UserDefinedType:     std::vector<X2D::Polygon<int> *,std::allocator<X2D::Polygon<int> *> >
// 
// Data           :   this+0x1094, Member, Type: struct StructNPC::NPCDeadHandler *, m_pDeadHandler
        public Roamer m_pRoamer; // Data           :   this+0x1098, Member, Type: struct StructRoamer *, 
// Function       :   public struct StructNPC & operator=(const struct StructNPC &)
// Function       :   public void * __vecDelDtor(unsigned int)

    }
}
